package com.lonelymeko.summer;


import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

public class ShishouApplicatonContext {
    private Class configClass;
    private final Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();
    private final Map<String,Object> singleton = new HashMap<>();
    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();
    public ShishouApplicatonContext(Class configClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        this.configClass = configClass;
        /**
         * 扫描
         */
        scan(configClass);
        //如果是单例放入单例池 遍历map
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            if(entry.getValue().getScope().equals("singleton")){
                singleton.put(entry.getKey(), getBean(entry.getKey()));
            }

        }



    }

    //一级搜索 根据beanName查找Bean对象

    public Object getBean(String beanName) {
        if(!beanDefinitionMap.containsKey(beanName)){
            throw new RuntimeException("No bean found for name: " + beanName);
        }
        //找到对应BeanDefinition
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

        Object object;

        //判断是单例还是实例 实例:创建对象 单例:从单例池中取出对象返回
        if(beanDefinition.getScope().equals("singleton")){
            object = singleton.get(beanName);
        }else{
            //实例
            object = createBean(beanName,beanDefinition);
        }



        return object;



    }




    //先根据Class类型找再根据BeanName(调用上面方法)找
    public Object getBean(String beanName,Class<?> type){
        var match = beanDefinitionMap.entrySet().stream()
                .filter(entry -> type.isAssignableFrom(entry.getValue().getType()))
                .toList();
        if (match.size()==1) {
            return getBean(match.get(0).getKey());
        }
        //有多个bean符合type
        var matchName = match.stream().filter(entry -> entry.getKey().equals(beanName))
                .toList();
        if (matchName.size()==1) {
            return getBean(match.get(0).getKey());
        }
        throw new RuntimeException("No bean found for name: " + beanName);





    }
    public Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class<?> type = beanDefinition.getType();
        Constructor<?> constructor;
        try {
            constructor = type.getConstructor();
        } catch (NoSuchMethodException e) {
            constructor = Stream.of(type.getDeclaredConstructors())
                    .filter(c -> c.getParameterCount() > 0)
                    .findFirst()
                    .orElse(null);

        }
        if (constructor == null) {
            throw new RuntimeException("No suitable constructor found for bean: " + beanName);
        }
        //stream流 把参数转成object

        Object[] objects = Stream.of(constructor.getParameters())
                .map(p -> {
                    Class<?> pType = p.getType();
                    String pName = p.getName();
//                    System.out.println(pName);

                        Object bean = getBean(pName, pType);
                        return bean;

                }).toArray(Object[]::new);


        Object object;
        try {
            //创建对象
            object = constructor.newInstance(objects);
        } catch (Exception e) {
            throw new RuntimeException("Failed to create bean: " + beanName, e);
        }
        object = setAutoWired(object);
        //初始化方法
        if(object instanceof InitializingBean){
            ((InitializingBean) object).afterPropertiesSet();
        }
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            //后置方法
            object = beanPostProcessor.postProcessBeforeInitialization(object,beanName);
        }



        return object;
    }


    /**
     * 扫描
     */
    private void scan(Class configClass) throws ClassNotFoundException {
        //检测AppConfig是否配置扫描路径
        if(configClass.isAnnotationPresent(ComponentScan.class)){
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            //获取value com. ...
            String value = componentScanAnnotation.value();
            value = value.replace(".", "/");
//            System.out.println(value);
            ClassLoader classLoader = ShishouApplicatonContext.class.getClassLoader();
            URL resource = classLoader.getResource(value);
            //file:/F:/Programs/JavaPrograms/shishouSpring/target/classes/com/lonelymeko/shishou
            File file = new File(resource.getFile());
            //遍历要扫描的包
            if(file.isDirectory()){
                for (File listFile : file.listFiles()) {
                    String absolutePath = listFile.getAbsolutePath();
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    absolutePath = absolutePath.replace("\\",".");
//                    System.out.println(absolutePath);
                    //加载
                    Class aClass = classLoader.loadClass(absolutePath);
                    //判断是否标记Component
                    if(aClass.isAnnotationPresent(Component.class)){
                        //判断是否实现PostProcessor接口
                        if(BeanPostProcessor.class.isAssignableFrom(aClass)){
                            try {
                                BeanPostProcessor beanPostProcessor = (BeanPostProcessor) aClass.getConstructor().newInstance();
                                beanPostProcessorList.add(beanPostProcessor);
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            }
                        }
                        Component component = (Component) aClass.getAnnotation(Component.class);
                        String beanName = component.value();
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setType(aClass);
                        //Scope 是否是单例还是实例
                        if(aClass.isAnnotationPresent(Scope.class)){
                            Scope scope = (Scope) aClass.getAnnotation(Scope.class);
                            if(scope.value().equals("singleton")){
                                //单例
                                beanDefinition.setScope("singleton");
                            }else{
                                //实例 这里简单判断
                                beanDefinition.setScope("prototype");
                            }

                        }else{
                            //默认单例
                            beanDefinition.setScope("singleton");

                        }
                        beanDefinitionMap.put(beanName,beanDefinition);
                    }

                }
            }

        }
    }
    /**
     * 注入 这里知识粗暴getName查找
     * @param instance
     * @return
     */
    private Object setAutoWired(Object instance) {
        if (instance != null){
            for (Field field : instance.getClass().getDeclaredFields()) {
                if(field.isAnnotationPresent(Autowired.class)){
                    String name = field.getName();
//                    System.out.println(name);
                    field.setAccessible(true);
                    try {
                        field.set(instance, getBean(name));
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException("没有找到这个属性值");
                    }
                }
            }
        }

        return instance;
    }
}
